package top.lyjwn.todo.aop.filter;

import com.alibaba.fastjson2.JSONObject;
import com.alibaba.nacos.common.http.param.MediaType;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.lyjwn.todo.aop.log.http.HttpLogE;
import top.lyjwn.todo.aop.log.http.HttpLogHandle;
import top.lyjwn.todo.aop.log.http.request.ServletRequestWrapper;
import top.lyjwn.todo.aop.log.http.response.ServletResponseWrapper;

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import top.lyjwn.todo.common.lang.TodoException;
import top.lyjwn.todo.common.template.R;
import top.lyjwn.todo.common.utils.JacksonUtil;
import top.lyjwn.todo.common.utils.UniqueUtil;

import java.io.IOException;
import java.text.MessageFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Optional;

public class TodoFilter implements Filter {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private HttpLogHandle httpLogHandle;

    private FilterExceptionHandle filterExceptionHandle;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        logger.debug("Filter-ing");
        String method = request.getMethod();
        if (method.equalsIgnoreCase("OPTIONS")) {
            String origin = request.getHeader("Origin");
            response.setHeader("Access-Control-Allow-Origin", origin);
            response.setHeader("Access-Control-Allow-Methods", "*");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Allow-Headers",
                    "Content-Type,XFILENAME,XFILECATEGORY,XFILESIZE,platform,token,authorization");
            response.setHeader("Access-Control-Allow-Credentials", "true");
            //response.setHeader("token",response.getHeader("token") == null || response.getHeader("token").isEmpty() ? request.getHeader("token") : response.getHeader("token"));
//			filterChain.doFilter(servletRequest, servletResponse);
//			response.setStatus(200);
            response.getWriter().write("OPTIONS returns OK");
//			servletResponse.getOutputStream().write("success".getBytes("utf-8"));
        } else {
            String uuid = UniqueUtil.getUUID();
            ServletRequestWrapper servletRequestWrapper = new ServletRequestWrapper(uuid, request);
            ServletResponseWrapper servletResponseWrapper = new ServletResponseWrapper(uuid, response);
            try {
                filterChain.doFilter(servletRequestWrapper, servletResponseWrapper);
            } catch (Exception e) {
                HttpLogE httpLogE = new HttpLogE().setRequest(servletRequestWrapper);
                if (e instanceof TodoException todoException) {
                    if (Optional.ofNullable(todoException.getR()).isPresent()) {
                        httpLogE.setResponseStatus(todoException.getR().getCode());
                    }
                }
                logger.error("Request failed", e);
                String invalidRequest;
                if (Optional.ofNullable(this.filterExceptionHandle).isPresent()) {
                    invalidRequest = this.filterExceptionHandle.toMsg(e);
                } else {
                    R error = R.init().error(500, "Invalid request");
                    ObjectMapper mapper = new ObjectMapper();
                    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略null值
                    invalidRequest = mapper.writeValueAsString(error);
                }
                httpLogE.setEndTime(LocalDateTime.now());
                httpLogE.setResponseContent(invalidRequest);
                httpLogE.setResponseContentType("application/json");
                httpLogHandle.write(httpLogE);
                response.getWriter().write(invalidRequest);
            }finally {
                servletResponseWrapper.copyBodyToResponse();
            }
        }
    }

    public void setFilterExceptionHandle(FilterExceptionHandle filterExceptionHandle) {
        this.filterExceptionHandle = filterExceptionHandle;
    }

    public void setHttpLogHandle(HttpLogHandle httpLogHandle) {
        this.httpLogHandle = httpLogHandle;
    }

    @Override
    public void destroy() {
        logger.info("Filter-unload");
    }

    @Override
    public void init(FilterConfig FilterConfig) throws ServletException {
        logger.info("Filter-inti");
    }
}
